/****************************************************************************/    
/* NAME:           TSC_2046.c                                               */    
/* PURPOSE:        Driver for touch pad tsc_2046                            */    
/* CREATED_BY:     Vyx                                                      */    
/* CREATION_DATE:  03/08/2012                                               */ 
/************************************** (C) Copyright 2012 AquaLink *********/

#include "stm32f10x.h"	    
#include "TSC_2046.h"  
#include "stdio.h"

void GetScreenZone()
{
    uint16_t X = 0;
    uint16_t Y = 0; 
    uint16_t temp = 0;

    X = TSC2046_MeasureX();
    Y = TSC2046_MeasureY();
    temp = TSC2046_ReadAmbiantTemp();
        
    X = X & 0xFFF;
    Y = Y & 0xFFF;

    printf("X = %d, Y = %d, T = %d\r\n", X, Y, temp);

    SpiDelay(100000);
}

/**    
  * @brief  Init driver
  * @param  None  
  * @retval None  
  */
void TSC2046_Init()
{
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 , ENABLE);

    /* Configure one bit for preemption priority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    /* Enable the EXTI9_5 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn  ;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6);

    /* Configure Key Button EXTI Line to generate an interrupt on falling edge */  
    EXTI_InitStructure.EXTI_Line = EXTI_Line6;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    TSC2046_SPI_config();
}	

/**    
  * @brief  Init spi periph
  * @param  None  
  * @retval None  
  */
void TSC2046_SPI_config()
{
    SPI_InitTypeDef   SPI_InitStructure;

	SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL              = SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA              = SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;  
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; 
	SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial     = 7;
	SPI_Init(SPI1,&SPI_InitStructure);

	SPI_Cmd(SPI1,ENABLE);
}

/**    
  * @brief  Write byte on Spi and return response
  * @param  Data to be write  
  * @retval Data read  
  */
unsigned char TSC2046_WriteByte(unsigned char data)
{
  unsigned char Data = 0;

  /* Wait until the transmit buffer is empty */
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);
  
  /* Send the byte */
  SPI_I2S_SendData(SPI1,data);

  /* Wait until a data is received */
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);
  /*Get the received data */
  Data = SPI_I2S_ReceiveData(SPI1);

  /* Return the shifted data */
  return Data;
}

void SpiDelay(unsigned int DelayCnt)
{
	unsigned int i;
	for(i=0;i<DelayCnt;i++);
}

/**    
  * @brief  Read current temperature build in tsc2046
  * @param  None
  * @retval Temp read  
  */
uint16_t TSC2046_ReadAmbiantTemp()
{
   uint16_t temp = 0;

   /* chip select low */
   SPI_TOUCH_CS_LOW();

   SpiDelay(10);
   
   /* write command to read temp */
   TSC2046_WriteByte(0x80);
   SpiDelay(10);
   temp = TSC2046_WriteByte(0x00);
   temp <<= 8;
   temp += TSC2046_WriteByte(0x00);
   SpiDelay(10);

   /* chip select high */
   SPI_TOUCH_CS_HIGH();

   temp = temp>>3;
   return (temp);
}

/**    
  * @brief  Read X pressed position
  * @param  None
  * @retval Raw X position
  */
uint16_t TSC2046_ReadRawX(void)
{
   uint16_t x = 0;

   SPI_TOUCH_CS_LOW();

   SpiDelay(10);
   TSC2046_WriteByte(0xD0);
   SpiDelay(10);
   x = TSC2046_WriteByte(0x00);
   x <<= 8;
   x += TSC2046_WriteByte(0x00);
   SpiDelay(10);

   SPI_TOUCH_CS_HIGH();

   x  = x>>3;
   x &= 0xFFF;

   return (x);
}

/**    
  * @brief  Read Y pressed position
  * @param  None
  * @retval Raw Y position 
  */
uint16_t TSC2046_ReadRawY(void)
{
  uint16_t y = 0;

  SPI_TOUCH_CS_LOW();

  SpiDelay(10);

  TSC2046_WriteByte(0x90);
  SpiDelay(10);
  y=TSC2046_WriteByte(0x00);
  y<<=8;
  y+=TSC2046_WriteByte(0x00);
  SpiDelay(10);

  SPI_TOUCH_CS_HIGH();

  y  = y>>3;
  y &= 0xFFF;

  return (y);
}

/**    
  * @brief  Read virtual value of X in pixel
  * @param  None
  * @retval X value
  */
int32_t TSC2046_MeasureX(void)
{
    unsigned char t = 0;
    unsigned char t1 = 0;
    unsigned char count = 0;
    uint16_t databuffer[10]={5,7,9,3,2,6,4,0,3,1};
    uint16_t temp=0;
    uint16_t X = 0;

    while(count<10)
    {
        databuffer[count] = TSC2046_ReadRawX();
        count++;
    }

    do
    {
    t1 = 0;
    for(t=0; t < count-1; t++)
    {
      if(databuffer[t] > databuffer[t+1])
      {
        temp            = databuffer[t+1];
        databuffer[t+1] = databuffer[t];
        databuffer[t]   = temp;
        t1              = 1;
      }
    }
    }
    while(t1);

    X = (databuffer[3]+databuffer[4]+databuffer[5])/3;
    
	return (X);
}

/**    
  * @brief  Read virtual value of Y in pixel
  * @param  None
  * @retval Y value
  */
int32_t TSC2046_MeasureY(void) 
{
   unsigned char t = 0;
  unsigned char t1 = 0;
  unsigned char count = 0;
	uint16_t databuffer[10]={5,7,9,3,2,6,4,0,3,1};
	uint16_t temp=0;
  uint16_t Y = 0;

  while(count<10)
	{
		databuffer[count] = TSC2046_ReadRawY();
		count++;
	}

  do
  {
    t1 = 0;
    for(t=0; t < count-1; t++)
    {
      if(databuffer[t] > databuffer[t+1])
      {
        temp            = databuffer[t+1];
        databuffer[t+1] = databuffer[t];
        databuffer[t]   = temp;
        t1              = 1;
      }
    }
  }
  while(t1);
  
  Y = (databuffer[3]+databuffer[4]+databuffer[5])/3;
    
	return (Y);
}
